<?php
/* 
 * PHP File Upload Class
 *
 * Simply setup the class and then call  save()
 *   $uploader = new FileUpload($source);
 *   $source : fieldname in html form
 *              or url
 *  
 * To process upload and save to file
 *   echo $uploader->save();
 *
 * Change log:
 *   2010/10/20: added invalid_source property
 *   2010/12/06: modified __construct +is_file() 
 */
class FileUpload {
  protected $type = ''; # http_post | copy_from_url | local_file
  protected $allowed_type = array(); 
  protected $invalid_source = 0; # 0: false, assume it is valid source
  public $maxSize = 5120000; # max size for file upload in bytes
  public $ext = '';
  // input
  public $url = '';
  public $local_path = '';
  public $fieldname = '';
  
  // output
  public $full_path=''; # full path for saving the file

  protected $debug=0;

	/*  support 3 type of file upload: file upload / server folder / copy_url
	 *
	 *   @Method:      __construct 
	 *   @Parameters:   2
	 *   @Param-1:      fieldname in html form
	 *                  or url
	 *   @Param-2:      optional maximium size
	 *   @Description:   Constructor method for PHP 5
	 *
	 */
	function __construct($fieldname_or_url, $allowed_type='',$maxSize = 5120000){
	  //echo('Upload: '.$fieldname_or_url."\n");
	  $this->maxSize = $maxSize; # Bugme: not checked yet
	  $this->allowed_type  = !empty_string($allowed_type) ? explode(',', $allowed_type):array() ; 
	  if (isset($_FILES[$fieldname_or_url]) && is_uploaded_file($_FILES[$fieldname_or_url]['tmp_name'])){
	  	$uploaded_filename = $_FILES[$fieldname_or_url]['name'];
	  	$path_parts = pathinfo($uploaded_filename);
	  	$this->ext  = $path_parts['extension'];
	  
	  	$this->type = 'http_post';
	  	$this->fieldname = $fieldname_or_url;
	  } elseif (! empty($fieldname_or_url)) { # URL or local path
	  	$path_parts = pathinfo($fieldname_or_url);
	  	#$this->ext  = $path_parts['extension']; # pls note some image/file being served by program will not have correct extension
	  	$this->ext  = get_hash_param($path_parts, 'extension', '');
	  	if ( preg_match('/^http:/', $fieldname_or_url) ){
	  		$this->type = 'copy_from_url';
	  		$this->url = $fieldname_or_url;
	  	} elseif (file_exists($fieldname_or_url) && is_file($fieldname_or_url)){
	  		$this->type = 'local_file';
	  		$this->local_path = $fieldname_or_url;
	  	} else {
	  	  $this->invalid_source  = 1; 
	  	}
	  }  else {
	    $this->invalid_source  = 1; 
	  }
	  
	
	  #if (empty_string($this->type)){
	  #	// invallid source
	  #  $this->debug('FileUpload: Invalid Source.');
	  #}
	}

  /* Return 1: allowed
   *        0: not allowed
   */
  function in_allowed_type($ext){
    if (empty($this->allowed_type)) return 1; # empty array, allow all
    
    $pos = strpos($ext, '?'); #has question mark ? in string
	  if ($pos !== false){ # has ?, may be random number added by cms
	  	list($ext, $random) = explode('?', $ext); # remove the random part
	  }  
	  $ext = strtolower($ext);
    return in_array($ext, $this->allowed_type) ? 1 : 0;
  }

  function debug($str){
   	if ($this->debug == 0) return;
		#require_once('Debug.lib.php');
	    debug_log('dummy', $str);
  }


/* $path + $filename = full path of where the file to save to
 * $dummy_setting is not use in fileUpload. But will be used in child class ImageUpload
 *                
 */
function save($full_path, $dummy_setting=array()){ 
	if ($this->invalid_source==1 || empty_string($this->type) ){
		#echo "FileUpload: Invalid Source.\n";
		return array(10, 'FileUpload: Invalid Source.');
	}
	$this->full_path = $full_path;
	
	#$temp = realpath($full_path);//cannot call on non-exists file
	$dirname = dirname($full_path);	
	if (!file_exists($dirname)){
    $this->debug("  FileUpload:Create dir: $dirname");
	  mkdir($dirname, 0775, true);  # recursive create directory
	  chmod($dirname, 0755); 
  }
	
	#error_log("Writing to path: $full_path\n");
	$type = $this->type;
	if ($type == 'http_post'){
		return $this->process_uploaded_file();
	} elseif ($type == 'copy_from_url'){
		return $this->save_from_url();
	} elseif ($type == 'local_file'){
		return $this->copy_local_file();
	}
	
	return array(11, 'invalid upload parameter?');
}


/*
 * get file extension
 * file extension is guess when file is uploaded, not accurate
 */
function get_extension(){
//	$ext=strrchr($url,".");
//	if($ext!=".gif" && $ext!=".jpg" && $ext!=".png"){
//		echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><script>alert("Sorry,url can be jpe\gif\png image only¡I");location="javascript:history.go(-1);"</script>';
//		exit();
//	}	

	return $this->ext;
}



protected function process_uploaded_file(){
  $full_path = $this->full_path;
  $fieldname = $this->fieldname;
  //set the location of the file
  
  //check to make sure the file isnt too big
  if($this->maxSize > 0  && $_FILES[$fieldname]['size'] > $this->maxSize){
    return array(12, "The uploaded file (file size) was too large");
  }
   
  $filename =  $_FILES[$fieldname]['name'];
  $this->ext =  pathinfo($filename, PATHINFO_EXTENSION) ;
  if (! $this->in_allowed_type($this->ext)){
   	return array(13, "File type not supported");
  }
  
  #$uploaded_type = $_FILES[$fieldname]['type']; // mime type
   
	//check to make sure the file is of the allowed types            
//	if(!in_array($_FILES[$fieldname]['type'], $this->arrAllowedTypes)){
//	   return "This type of file is not allowed to be uploaded.";
//	}
	
   if(!move_uploaded_file($_FILES[$fieldname]['tmp_name'], $full_path)){
   	  $this->debug("FileUpload.php process_uploaded_file(): Failed to upload $fieldname. (path does not exists/ over size limit?");
      return array(14, "There was an error saving the file.");
   }else{
      return array(0, "File Successfully Uploaded.");
   }
}


protected function copy_local_file(){
	$full_path = $this->full_path;
  // bugme: add permission check?
  $this->ext =  pathinfo($this->local_path, PATHINFO_EXTENSION) ;
  if (! $this->in_allowed_type($this->ext)){
   	return array(13, "File type not supported");
  }

  
	if (copy($this->local_path, $full_path)){ # copy success
	  return array(0, "File Successfully Uploaded.");
  } 
   
  return array(14, "There was an error saving the file.");
}



/*
 * save file from URL to file
 * ??? no error detected yet... 
 */
protected function save_from_url(){
	$full_path = $this->full_path;

  //bugme, change to check mime_type later
  $this->ext =  pathinfo($this->url, PATHINFO_EXTENSION) ;
  if (! $this->in_allowed_type($this->ext)){
   	return array(13, "File type not supported");
  }
	
	$this->debug("Save from URL to: $full_path");
	// the following code didn't get/check content type
//	ob_start();
//	readfile($this->url);	
//	$img = ob_get_contents();
//	ob_end_clean();

  /*
    file_get_contents is similar to file(), except that file_get_contents() returns the file in a string , starting at the specified offset up to maxlen bytes. On failure, file_get_contents() will return FALSE.
    file_get_contents() is the preferred way to read the contents of a file into a string. It will use memory mapping techniques if supported by your OS to enhance performance. 
   */
  
/*  
 if(!@copy('http://someserver.com/somefile.zip','./somefile.zip'))
{
    $errors= error_get_last();
    echo "COPY ERROR: ".$errors['type'];
    echo "<br />\n".$errors['message'];
} else {
    echo "File copied from remote!";
}
*/    
    
  // some sample has implemented user agent. pls fix it.  
	$img = file_get_contents($this->url);
	if ($img === false){
		return array(15, 'Failed to get '.$this->url.' from remote');
	}
	
	$size = strlen($img);	
	$fp=@fopen($full_path, "a");
	fwrite($fp,$img);
	fclose($fp);
	return array(0, "File Successfully Uploaded.");  
}

}// end FileUpload class

?>
